﻿using System.Collections;
using System.Collections.Generic;
using GameFramework.Localization;
using GameFramework.Event;
using UnityGameFramework.Runtime;
using GameFramework.Procedure;
using GameFramework;
using TowerDefence_Zombie.Data;
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
using System;

namespace TowerDefence_Zombie
{
    public class ProcedureLevel : ProcedureBase
    {
        public LevelControl LevelControl { get; private set; }

        public GuideControl GuideControl { get; private set; }

        protected override void OnEnter(ProcedureOwner procedureOwner)
        {
            base.OnEnter(procedureOwner);

            DataLevel dataLevel = GameEntry.Data.GetData<DataLevel>();
            LevelManager levelPathManager = UnityEngine.GameObject.Find("LevelManager").GetComponent<LevelManager>();
            if (levelPathManager == null)
            {
                Log.Error("Can not find LevelPathManager instance in scene");
                return;
            }
            GuideControl = new GuideControl();
            LevelControl = LevelControl.Create(levelPathManager, this);

            GameEntry.Event.Subscribe(LevelStateChangeEventArgs.EventId, OnLevelStateChange);
            GameEntry.Event.Subscribe(GameEndEventArgs.EventId, OnGameOver);
            GameEntry.Event.Subscribe(StartWaveEventArgs.EventId, OnStartWave);
            GameEntry.Event.Subscribe(SpawnEnemyEventArgs.EventId, OnSpawnEnemy);
            GameEntry.Event.Subscribe(HideEnemyEventArgs.EventId, OnHideEnemyEntity);
            GameEntry.Event.Subscribe(ShowEntityInLevelEventArgs.EventId, OnShowEntityInLevel);
            GameEntry.Event.Subscribe(HideEntityInLevelEventArgs.EventId, OnHideEntityInLevel);
            GameEntry.Event.Subscribe(ChangePlacementAreaEventArgs.EventId, OnPlacementAreaChange);

            GameEntry.Event.Subscribe(ShowEntityBeDamageEventArgs.EventId, OnShowEntityBeDamage);
            GameEntry.Event.Subscribe(HideEntityBeDamageEventArgs.EventId, OnHideEntityBeDamage);

            GameEntry.Event.Subscribe(UnlockPlacementEventArgs.EventId, UnLockPlacementArea);
            GameEntry.Event.Subscribe(HighlightPlacementEventArgs.EventId, HighLightPlacementArea);

            GameEntry.UI.OpenDownloadForm();
            LevelControl.OnEnter();

            GameEntry.Event.Fire(this, StartWaveEventArgs.Create());
            dataLevel.ChangeLevelState(EnumLevelState.Normal);

            GameEntry.Sound.PlaySound(EnumSound.GameBGM, null);

            //___打点
            DataPlayer dataPlayer = GameEntry.Data.GetData<DataPlayer>();
            int isFirstLogin = dataPlayer.GetOnlineTime() == 0 ? 1 : 0;
            Dictionary<string, string> dic = new()
            {
                { "U", UPTrace.UPTraceApi.getUserId() },
                { "I", "guest" },
                { "A1", dataPlayer.GetCurrency(CurrencyType.Coin).ToString() },
                { "A2", dataPlayer.GetCurrency(CurrencyType.Gem).ToString() },
                { "F", isFirstLogin.ToString() },
                { "L", "0" },
            };
            UPTrace.UPTraceApi.traceDictionary("T0F", dic);

            var curBattleLevel = dataPlayer.GetCurBattleLevel();
            Dictionary<string, string> dicLevel = new()
            {
                { "U", UPTrace.UPTraceApi.getUserId() },
                { "G", curBattleLevel.ToString() },
                { "L", "0" },
                { "H1", "None_001" },
                { "H2", "None_002" },
                { "H3", "None_003" },
            };
            UPTrace.UPTraceApi.traceDictionary("T08", dicLevel);
        }

        protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);

            if (GuideControl == null) return;

            GuideControl.Update(elapseSeconds, realElapseSeconds);

            if (GuideControl.IsCanUpdateGame() == false) return;

            LevelControl?.Update(elapseSeconds, realElapseSeconds, GuideControl.IsPauseGame, GuideControl.IsAllowOperaSceneTower);

            if (GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.RemainDoubleAttackTime > 0)
            {
                float remainTime = GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.RemainDoubleAttackTime;
                remainTime -= elapseSeconds;
                if (remainTime < 0)
                    remainTime = 0;
                GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.RemainDoubleAttackTime = remainTime;
                GameEntry.Event.Fire(this, UpdateDoubleAtkSkillTimeEventArgs.Create(remainTime));
            }
            ;
            if (GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.RemainDoubleGoldTime > 0)
            {
                float remainTime = GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.RemainDoubleGoldTime;
                remainTime -= elapseSeconds;
                if (remainTime < 0)
                    remainTime = 0;
                GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.RemainDoubleGoldTime = remainTime;
                GameEntry.Event.Fire(this, UpdateDoubleGlobTimeEventArgs.Create(remainTime));
            }

            if (GameEntry.Data.GetData<DataPlayer>().GetPlayerData().CarSkillData.isUnlock)
            {
                float remainTime = GameEntry.Data.GetData<DataPlayer>().GetPlayerData().CarSkillData.RemainUnlockTime;
                if (remainTime > 0)
                {
                    remainTime -= elapseSeconds;
                    if (remainTime < 0)
                        remainTime = 0;
                    GameEntry.Data.GetData<DataPlayer>().GetPlayerData().CarSkillData.RemainUnlockTime = remainTime;
                    GameEntry.Event.Fire(this, UpdateCarSkillTimeEventArgs.Create(remainTime));
                }
            }
        }

        protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);

            GameEntry.Event.Unsubscribe(LevelStateChangeEventArgs.EventId, OnLevelStateChange);
            GameEntry.Event.Unsubscribe(GameEndEventArgs.EventId, OnGameOver);
            GameEntry.Event.Unsubscribe(StartWaveEventArgs.EventId, OnStartWave);
            GameEntry.Event.Unsubscribe(SpawnEnemyEventArgs.EventId, OnSpawnEnemy);
            GameEntry.Event.Unsubscribe(HideEnemyEventArgs.EventId, OnHideEnemyEntity);
            GameEntry.Event.Unsubscribe(ShowEntityInLevelEventArgs.EventId, OnShowEntityInLevel);
            GameEntry.Event.Unsubscribe(HideEntityInLevelEventArgs.EventId, OnHideEntityInLevel);
            GameEntry.Event.Unsubscribe(ChangePlacementAreaEventArgs.EventId, OnPlacementAreaChange);


            GameEntry.Data.GetData<DataPlayer>().GetPlayerData().PlayerSkillData.BeOfflineTime = DateTime.Now.ToString();
            LevelControl.Quick();

            GameEntry.Sound.StopMusic();
            ReferencePool.Release(LevelControl);
            LevelControl = null;
        }

        private void OnStartWave(object sender, GameEventArgs e)
        {
            StartWaveEventArgs ne = (StartWaveEventArgs)e;
            if (ne == null)
                return;

            LevelControl.StartWave();
        }

        private void OnLevelStateChange(object sender, GameEventArgs e)
        {
            LevelStateChangeEventArgs ne = (LevelStateChangeEventArgs)e;
            if (ne == null)
                return;

            if (ne.CurrentState == EnumLevelState.Pause)
            {
                LevelControl.Pause();
            }
            else if (ne.LastState == EnumLevelState.Pause)
            {
                LevelControl.Resume();
            }
        }

        private void OnGameOver(object sender, GameEventArgs e)
        {
            GameEndEventArgs ne = (GameEndEventArgs)e;
            if (ne == null)
                return;

            LevelControl.Gameover(ne.EndType, ne.IsForceEnd);
        }

        private void OnPlacementAreaChange(object sender, GameEventArgs e)
        {
            ChangePlacementAreaEventArgs ne = (ChangePlacementAreaEventArgs)e;
            if (ne == null)
                return;

            LevelControl.OnPlacementAreaChange(ne.AreaId, ne.TowerId, ne.TowerLevel, ne.IsUpgrade);
        }

        private void OnSpawnEnemy(object sender, GameEventArgs e)
        {
            SpawnEnemyEventArgs ne = (SpawnEnemyEventArgs)e;
            if (ne == null)
                return;

            LevelControl.SpawnEnemy(ne.EnemyId, ne.CoinNum);
        }

        private void OnHideEnemyEntity(object sender, GameEventArgs e)
        {
            HideEnemyEventArgs ne = (HideEnemyEventArgs)e;
            if (ne == null)
                return;

            LevelControl.HideEnemyEntity(ne.EntityId);
        }

        private void OnShowEntityInLevel(object sender, GameEventArgs e)
        {
            ShowEntityInLevelEventArgs ne = (ShowEntityInLevelEventArgs)e;
            if (ne == null)
                return;

            LevelControl.ShowEntity(ne.EntityId, ne.Type, ne.ShowSuccess, ne.EntityData);
        }

        private void OnHideEntityInLevel(object sender, GameEventArgs e)
        {
            HideEntityInLevelEventArgs ne = (HideEntityInLevelEventArgs)e;
            if (ne == null)
                return;

            LevelControl.HideEntity(ne.EntityId);
        }

        private void OnShowEntityBeDamage(object sender, GameEventArgs e)
        {
            ShowEntityBeDamageEventArgs ne = (ShowEntityBeDamageEventArgs)e;
            if (ne == null)
                return;
            LevelControl.SpawmBeDamagedEnemy(ne.EntityId, ne.Position, ne.Damage, ne.isPoison);
        }

        private void OnHideEntityBeDamage(object sender, GameEventArgs e)
        {
            HideEntityBeDamageEventArgs ne = (HideEntityBeDamageEventArgs)e;
            if (ne == null)
                return;
            LevelControl.HideEntity(ne.EntityId);
        }

        private void UnLockPlacementArea(object sender, GameEventArgs e)
        {
            UnlockPlacementEventArgs ne = (UnlockPlacementEventArgs)e;
            if (ne == null) return;

            LevelControl.UnlockPlacementArea(ne.AreaId);
        }

        private void HighLightPlacementArea(object sender, GameEventArgs e)
        {
            HighlightPlacementEventArgs ne = (HighlightPlacementEventArgs)e;
            if (ne == null) return;

            LevelControl.HighlightPlacementArea(ne.AreaId, ne.HighlightState);
        }
    }
}